home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / bin / man2html < prev    next >
Text File  |  1995-07-05  |  14KB  |  448 lines

  1. #! /usr/skunk/bin/perl
  2. ##---------------------------------------------------------------------------##
  3. ##  File:
  4. ##      man2html
  5. ##  Author:
  6. ##      Earl Hood       ehood@convex.com
  7. ##  Description:
  8. ##      man2html is a Perl program to convert formatted nroff output
  9. ##    to HTML.
  10. ##    
  11. ##    Recommend command-line options based on platform:
  12. ##
  13. ##    Platform        Options
  14. ##    ---------------------------------------------------------------------
  15. ##    c2mp            <None, the defaults should be okay>
  16. ##    hp9000s700/800        -leftm 1 -topm 8
  17. ##    sun4            -sun
  18. ##    ---------------------------------------------------------------------
  19. ##
  20. ##---------------------------------------------------------------------------##
  21. ##  Copyright (C) 1994  Earl Hood, ehood@convex.com
  22. ##
  23. ##  This program is free software; you can redistribute it and/or modify
  24. ##  it under the terms of the GNU General Public License as published by
  25. ##  the Free Software Foundation; either version 2 of the License, or
  26. ##  (at your option) any later version.
  27. ##  
  28. ##  This program is distributed in the hope that it will be useful,
  29. ##  but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. ##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31. ##  GNU General Public License for more details.
  32. ##  
  33. ##  You should have received a copy of the GNU General Public License
  34. ##  along with this program; if not, write to the Free Software
  35. ##  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  36. ##---------------------------------------------------------------------------##
  37.  
  38. require 'newgetopt.pl' || die "Unable to require newgetopt.pl\n";
  39.  
  40. ($PROG = $0) =~ s/.*\///;
  41. $VERSION = "2.0.2";
  42.  
  43. ## Backspace character:  Used in overstriking detection
  44. $bs = "\b";
  45.  
  46. ##    Associative array of section titles and their HTML tag wrapper.
  47. ##    This list allows customization of what HTML tag is used for
  48. ##    a given section head.
  49. ##
  50. ##    The section title can be a regular expression.  Therefore, one must
  51. ##    be careful about quoting special characters.
  52. ##
  53. %SectionHead = (
  54.  
  55.     '\S.*OPTIONS.*', '<H2>',
  56.     'AUTHORS?', '<H2>',
  57.     'BUGS', '<H2>',
  58.     'COMPATIBILITY', '<H2>',
  59.     'DEPENDENCIES', '<H2>',
  60.     'DESCRIPTION', '<H2>',
  61.     'DIAGNOSTICS', '<H2>',
  62.     'ENVIRONMENT', '<H2>',
  63.     'ERRORS', '<H2>',
  64.     'EXAMPLES', '<H2>',
  65.     'EXTERNAL INFLUENCES', '<H2>',
  66.     'FILES', '<H2>',
  67.     'LIMITATIONS', '<H2>',
  68.     'NAME', '<H2>',
  69.     'NOTES?', '<H2>',
  70.     'OPTIONS', '<H2>',
  71.     'REFERENCES', '<H2>',
  72.     'RETURN VALUE', '<H2>',
  73.     'SECTION.*:', '<H2>',
  74.     'SEE ALSO', '<H2>',
  75.     'STANDARDS CONFORMANCE', '<H2>',
  76.     'STYLE CONVENTION', '<H2>',
  77.     'SYNOPSIS', '<H2>',
  78.     'SYNTAX', '<H2>',
  79.     'WARNINGS', '<H2>',
  80.     '\s+Section.*:', '<H3>',
  81.  
  82. );
  83. $HeadFallback = '<H2>';  # Fallback tag if above is not found.
  84.  
  85. ##---------------------------------------------------------------------------
  86. ##-----------##
  87. ## MAIN Body ##
  88. ##-----------##
  89. {
  90. &get_cli_opts();
  91.  
  92. ## Check if processing a keyord search
  93. if ($K && $CGIURL) { &man_k(); exit 0; }
  94.  
  95. local($line,$tmp,$i,$head,$preindent,$see_also);
  96. $see_also = 1;
  97.  
  98. if (!$BARE) {
  99.     print STDOUT "<HTML>\n";
  100.     print STDOUT "<HEAD>\n",
  101.          "<TITLE>$TITLE</TITLE>\n",
  102.          "</HEAD>\n"  if $TITLE;
  103.     print STDOUT "<BODY>\n";
  104.     print STDOUT "<H1>$TITLE</H1>\n",
  105.          "<HR>\n"  if $TITLE;
  106. }
  107. print STDOUT "<PRE>\n";
  108. while(!eof(STDIN)) {
  109.     for ($i=0; $i < $hdsz; $i++) { <STDIN>; }
  110.     for ($i=0; $i < $txsz; $i++) {
  111.     $_ = <STDIN>;
  112.  
  113.     ## Try to check if line space is needed at page boundaries ##
  114.     if (!$NODEPAGE && ($i==0 || $i==($txsz-1)) && !/^\s*$/) {
  115.         /^(\s*)/;  $tmp = length($1);
  116.         if ($do) {
  117.         if ($tmp < $preindent) { print STDOUT "\n"; }
  118.         } else {
  119.         $do = 1;
  120.         }
  121.         $preindent = $tmp;
  122.     } else {
  123.         $do = 0;  $preindent = 0;
  124.     }
  125.  
  126.     ## Interpret line
  127.     $line = $_;
  128.     &entitize(*_);        # Convert [$<>] to entity references
  129.  
  130.     ## Create anchor links for manpage references
  131.     s/((((.$bs)+)?[\+_\.\w-])+\(((.$bs)+)?\d((.$bs)+)?\w?\))/&make_xref($1)/oge
  132.         if $CGIURL && $see_also;
  133.  
  134.     ## Emphasize underlined words
  135.     s/((_\010[^_])+[\.\(\)_]?(_\010[^_])+\)?)/&emphasize($1)/oge;
  136.     $secth = 0;
  137.     ## Check for strong text and headings
  138.     if ($SUN || /.\010./o) {
  139.         if (!$NOHEADS) {
  140.         $line =~ s/.\010//go;
  141.         $tmp = $HeadFallback;
  142.         foreach $head (keys %SectionHead) {
  143.             if ($line =~ /^$leftm$head/) {
  144.             $tmp = $SectionHead{$head};
  145.             $secth = 1;
  146.             last;
  147.             }
  148.         }
  149.         if ($secth || $line =~ /^$leftm\S/o) {
  150.             if ($CGIURL && $SEEALSO) {
  151.             if ($line =~ /SEE ALSO/o) { $see_also = 1; }
  152.             else { $see_also = 0; }
  153.             }
  154.             chop $line;
  155.             $_ = $tmp . $line . $tmp;
  156.             s%<([^>]*)>$%</$1>%;
  157.             $_ = "\n</PRE>\n" . $_ . "<PRE>\n";
  158.         } else {
  159.             s/(((.\010)+.)+)/&strongize($1)/oge;
  160.         }
  161.         } else {
  162.         s/(((.\010)+.)+)/&strongize($1)/oge;
  163.         }
  164.     }
  165.     print STDOUT;
  166.     }
  167.     for ($i=0; $i < $ftsz; $i++) { <STDIN>; }
  168. }
  169. print STDOUT "</PRE>\n",
  170.          "</BODY>\n",
  171.          "</HTML>\n"  unless $BARE;
  172. exit 0;
  173. }  ## End Main
  174. ##---------------------------------------------------------------------------
  175. sub get_cli_opts {
  176.     &usage unless
  177.     &NGetOpt(
  178.     "botm=i",    # Number of lines for bottom margin (def: 7)
  179.     "headmap=s",    # Filename of user section head map file
  180.     "leftm=i",    # Character width of left margin (def: 0)
  181.     "nodepage",    # Do not remove pagination lines
  182.     "noheads",    # Do not detect for section heads
  183.     "pgsize=i",    # Number of lines in a page (def: 66)
  184.     "title=s",    # Title of manpage (def: Not defined)
  185.     "topm=i",    # Number of lines for top margin (def: 7)
  186.     "sun",        # Section heads are not overstriked in input
  187.     "cgiurl=s",    # CGI URL for linking to other manpages
  188.     "seealso",    # Link to other manpages only in the SEE ALSO section
  189.     "k",        # Process input from 'man -k' output.
  190.     "bare",        # Leave out HTML, HEAD, BODY tags.
  191.     "help"        # Short usage message
  192.     );
  193.     &usage() if defined($opt_help);
  194.  
  195.     $pgsz = ($opt_pgsize ? $opt_pgsize : 66);
  196.     if (defined($opt_nodepage)) {
  197.     $hdsz = 0;
  198.     $ftsz = 0;
  199.     } else {
  200.     $hdsz = (defined($opt_topm) ? $opt_topm : 7);
  201.     $ftsz = (defined($opt_botm) ? $opt_botm : 7);
  202.     }
  203.     $txsz    = $pgsz - ($hdsz + $ftsz);
  204.     $leftmsz = (defined($opt_leftm) ? $opt_leftm : 0);
  205.     $leftm   = ' ' x $leftmsz;
  206.  
  207.     $TITLE   = ($opt_title ? $opt_title : "");
  208.     $NOHEADS = (defined($opt_noheads) ? 1 : 0);
  209.     $SUN     = (defined($opt_sun) ? 1 : 0);
  210.     $CGIURL  = ($opt_cgiurl ? $opt_cgiurl : "");
  211.     $SEEALSO = ($opt_seealso ? 1 : 0);
  212.     $K       = ($opt_k ? 1 : 0);
  213.     $BARE    = ($opt_bare ? 1 : 0);
  214.  
  215.     if (defined($opt_headmap)) {
  216.     require $opt_headmap || warn "Unable to read $opt_headmap\n";
  217.     }
  218. }
  219. ##---------------------------------------------------------------------------
  220. sub emphasize {
  221.     local($txt) = shift;
  222.     $txt =~ s/.\010//go;
  223.     $txt = "<EM>$txt</EM>";
  224.     $txt;
  225. }
  226. ##---------------------------------------------------------------------------
  227. sub strongize {
  228.     local($txt) = shift;
  229.     $txt =~ s/.\010//go;
  230.     $txt = "<STRONG>$txt</STRONG>";
  231.     $txt;
  232. }
  233. ##---------------------------------------------------------------------------
  234. sub entitize {
  235.     local(*txt) = shift;
  236.  
  237.     ## Check for special characters in overstrike text ##
  238.     $txt =~ s/_\010\&/&strike('_', '&')/geo;
  239.     $txt =~ s/_\010</&strike('_', '<')/geo;
  240.     $txt =~ s/_\010>/&strike('_', '>')/geo;
  241.  
  242.     $txt =~ s/(\&\010)+\&/&strike('&', '&')/geo;
  243.     $txt =~ s/(<\010)+</&strike('<', '<')/geo;
  244.     $txt =~ s/(>\010)+>/&strike('>', '>')/geo;
  245.  
  246.     ## Check for special characters in regular text.  Must be careful
  247.     ## to check before/after character in expression because it might be
  248.     ## a special character.
  249.     $txt =~ s/([^\010]\&[^\010])/&htmlize2($1)/geo;
  250.     $txt =~ s/([^\010]<[^\010])/&htmlize2($1)/geo;
  251.     $txt =~ s/([^\010]>[^\010])/&htmlize2($1)/geo;
  252. }
  253. ##---------------------------------------------------------------------------
  254. ##    htmlize2() is used by entitize.
  255. ##
  256. sub htmlize2 {
  257.     local($str) = shift;
  258.     $str =~ s/&/\&/g;
  259.     $str =~ s/</\</g;
  260.     $str =~ s/>/\>/g;
  261.     $str;
  262. }
  263. ##---------------------------------------------------------------------------
  264. ##    strike converts HTML special characters in overstriked text
  265. ##    into entity references.  The entities are overstriked so
  266. ##    strongize() and emphasize() will recognize the entity to be
  267. ##    wrapped in <STRONG>/<EM> tags.
  268. ##
  269. sub strike {
  270.     local($w, $char) = @_;
  271.     local($ret);
  272.     if ($w eq '_') {
  273.     if ($char eq '&') {
  274.         $ret = "_$bs\&_${bs}a_${bs}m_${bs}p_${bs};";
  275.     } elsif ($char eq '<') {
  276.         $ret = "_$bs\&_${bs}l_${bs}t_${bs};";
  277.     } elsif ($char eq '>') {
  278.         $ret = "_$bs\&_${bs}g_${bs}t_${bs};";
  279.     } else {
  280.         warn qq|Unrecognized character, "$char", passed to strike()\n|;
  281.     }
  282.     } else {
  283.     if ($char eq '&') {
  284.         $ret = "\&$bs\&a${bs}am${bs}mp${bs}p;${bs};";
  285.     } elsif ($char eq '<') {
  286.         $ret = "\&$bs\&l${bs}lt${bs}t;${bs};";
  287.     } elsif ($char eq '>') {
  288.         $ret = "\&$bs\&g${bs}gt${bs}t;${bs};";
  289.     } else {
  290.         warn qq|Unrecognized character, "$char", passed to strike()\n|;
  291.     }
  292.     }
  293.     $ret;
  294. }
  295. ##---------------------------------------------------------------------------
  296. ##    make_xref() was originally added to man2html by Maurice Cinquini
  297. ##    <mauricec@tplrd.tpl.oz.au> for use in the SEE ALSO section.  The
  298. ##    code has been modified to handle more general cases, and the routine
  299. ##    is called for all manpage cross-references throughout.
  300. ##
  301. ##    Specifically, I modified it to support the user's URL template for
  302. ##    linking to other manpages, support for [+_,-] in the title name,
  303. ##    and to handle <EM> tagging.
  304. ##
  305. sub make_xref {
  306.     local($str) = shift;
  307.     $str =~ s/.\010//go;            # Remove overstriking
  308.     local($title,$section,$subsection) =
  309.     ($str =~ /([\+_\.\w-]+)\((\d)(\w?)\)/);
  310.  
  311.     local($href) = (eval "\"$CGIURL\"");
  312.     qq|<STRONG><A HREF="$href">$str</A></STRONG>|;
  313. }
  314. ##---------------------------------------------------------------------------
  315. ##    man_k() process a keyword search.
  316. ##
  317. sub man_k {
  318.     local($line,$refs,$section,$subsection,$desc,$i,
  319.       %Sec1, %Sec1sub, %Sec2, %Sec2sub, %Sec3, %Sec3sub,
  320.       %Sec4, %Sec4sub, %Sec5, %Sec5sub, %Sec6, %Sec6sub,
  321.       %Sec7, %Sec7sub, %Sec8, %Sec8sub, %Sec9, %Sec9sub,
  322.       %SecN, %SecNsub, %SecNsec);
  323.  
  324.     print STDOUT "<HTML>\n";
  325.     print STDOUT "<HEAD>\n",
  326.          "<TITLE>$TITLE</TITLE>\n",
  327.          "</HEAD>\n"  if $TITLE;
  328.     print STDOUT "<BODY>\n";
  329.     print STDOUT "<H1>$TITLE</H1>\n",
  330.          "<HR>\n"  if $TITLE;
  331.     while ($line = <STDIN>) {
  332.     next if $line !~ /\(\d\w?\)\s*-/;
  333.     ($refs,$section,$subsection,$desc) =
  334.         $line =~ /^\s*(.*)\((\d)(\w?)\)\s*-\s*(.*)$/;
  335.     $refs =~ s/\s(and|or)\s/,/gi;    # Convert and/or to commas
  336.     $refs =~ s/\s//g;        # Remove all whitespace
  337.     $refs =~ s/,/, /g;        # Put space after comma
  338.     &htmlize(*desc);        # Check for special chars in desc
  339.     $desc =~ s/^(.)/\U$1/;        # Uppercase first letter in desc
  340.  
  341.     if ($section eq '1') {
  342.         $Sec1{$refs} = $desc; $Sec1sub{$refs} = $subsection;
  343.     } elsif ($section eq '2') {
  344.         $Sec2{$refs} = $desc; $Sec2sub{$refs} = $subsection;
  345.     } elsif ($section eq '3') {
  346.         $Sec3{$refs} = $desc; $Sec3sub{$refs} = $subsection;
  347.     } elsif ($section eq '4') {
  348.         $Sec4{$refs} = $desc; $Sec4sub{$refs} = $subsection;
  349.     } elsif ($section eq '5') {
  350.         $Sec5{$refs} = $desc; $Sec5sub{$refs} = $subsection;
  351.     } elsif ($section eq '6') {
  352.         $Sec6{$refs} = $desc; $Sec6sub{$refs} = $subsection;
  353.     } elsif ($section eq '7') {
  354.         $Sec7{$refs} = $desc; $Sec7sub{$refs} = $subsection;
  355.     } elsif ($section eq '8') {
  356.         $Sec8{$refs} = $desc; $Sec8sub{$refs} = $subsection;
  357.     } elsif ($section eq '9') {
  358.         $Sec9{$refs} = $desc; $Sec9sub{$refs} = $subsection;
  359.     } else {            # Catch all
  360.         $SecN{$refs} = $desc; $SecNsec{$refs} = $section;
  361.         $SecNsub{$refs} = $subsection;
  362.     }
  363.     }
  364.     &print_mank_sec(*Sec1, 1, *Sec1sub);
  365.     &print_mank_sec(*Sec2, 2, *Sec2sub);
  366.     &print_mank_sec(*Sec3, 3, *Sec3sub);
  367.     &print_mank_sec(*Sec4, 4, *Sec4sub);
  368.     &print_mank_sec(*Sec5, 5, *Sec5sub);
  369.     &print_mank_sec(*Sec6, 6, *Sec6sub);
  370.     &print_mank_sec(*Sec7, 7, *Sec7sub);
  371.     &print_mank_sec(*Sec8, 8, *Sec8sub);
  372.     &print_mank_sec(*Sec9, 9, *Sec9sub);
  373.     &print_mank_sec(*SecN, 'N', *SecNsub, *SecNsec);
  374.  
  375.     print STDOUT "</DL>\n",
  376.          "</BODY>\n",
  377.          "</HTML>\n";
  378. }
  379. ##---------------------------------------------------------------------------
  380. ##    print_mank_sec() prints out manpage cross-refs of a specific section.
  381. sub print_mank_sec {
  382.     local(*sec, $sect, *secsub, *secsec) = @_;
  383.     local(@array, @refs, $href, $item, $title, $subsection, $i, $section);
  384.     $section = $sect;
  385.  
  386.     @array = sort keys %sec;
  387.     if ($#array >= 0) {
  388.     print STDOUT "<H2>Section $section</H2>\n",
  389.              "<DL>\n";
  390.     foreach $item (@array) {
  391.         $section = $secsec{$item}  if $sect eq 'N';
  392.         @refs = split(/,/,$item);
  393.         $title = $refs[0];
  394.         $title  =~ s/\(\)//g;        # Watch out for extra ()'s
  395.         $subsection = $secsub{$item};
  396.         $href = eval "\"$CGIURL\"";        # Create HREF string
  397.         print STDOUT "<DT>\n";
  398.         $i = 0;
  399.         foreach (@refs) {
  400.         print STDOUT qq|<A HREF="$href">$_</A>|;
  401.         print STDOUT ", "  if $i < $#refs;
  402.         $i++;
  403.         }
  404.         print STDOUT " ($section$subsection)\n",
  405.              "<DD>\n",
  406.              $sec{$item}, "\n";
  407.     }
  408.     print STDOUT "</DL>\n";
  409.     }
  410. }
  411. ##---------------------------------------------------------------------------
  412. sub htmlize {
  413.     local(*str) = shift;
  414.     $str =~ s/&/\&/g;
  415.     $str =~ s/</\</g;
  416.     $str =~ s/>/\>/g;
  417.     $str;
  418. }
  419. ##---------------------------------------------------------------------------
  420. sub usage {
  421.     print STDOUT <<EndOfUsage;
  422. Usage: $PROG [ options ] < infile > outfile
  423. Options:
  424.   -bare            : Do not put in HTML, HEAD, BODY tags
  425.   -botm <#>        : Number of lines for bottom margin (def: 7)
  426.   -cgiurl <url>        : URL for linking to other manpages
  427.   -headmap <file>    : Filename of user section head map file
  428.   -help            : This message
  429.   -k            : Process a keyword search result
  430.   -leftm <#>        : Character width of left margin (def: 0)
  431.   -nodepage        : Do not remove pagination lines
  432.   -noheads        : Do not detect for section heads
  433.   -pgsize <#>        : Number of lines in a page (def: 66)
  434.   -seealso        : Link to other manpages only in the SEE ALSO section
  435.   -sun            : Section heads are not overstriked in input
  436.   -title <string>    : Title of manpage (def: Not defined)
  437.   -topm <#>        : Number of line for top margin (def: 7)
  438. Description:
  439.   $PROG takes formatted manpages from STDIN and converts it to HTML sent to
  440.   STDOUT.  The -topm and -botm arguments are the number of lines to the main
  441.   body text and NOT to the running headers/footers.
  442. Version:
  443.   $VERSION
  444.  
  445. EndOfUsage
  446.     exit 0;
  447. }
  448.